#include <stdio.h>
#include "Mem.h"
#include "ExceptionManager.h"
#include "Class.h"
#include "ExampleException.h"

void Trying(Class*Target, unsigned long int pArgsCount, va_list* pParams)
{
    unsigned long int* vLong;
    bool* vBoolean;
    printf("\nTrying Called\n");
    /* use parameters */
    if(pArgsCount > 0)
    {
        vLong = va_arg(*pParams, unsigned long int*);
        if(pArgsCount > 1)
        {
            vBoolean = va_arg(*pParams, bool*);
            printf("\nTransmited parameters :\n\tUnsigned long = 0x%X,\n\tBoolean = %s.\n", *vLong, (*vBoolean)?"True":"False");
            *vLong = 7;
            *vBoolean = true;
        }
    }

    /* Simulate an incorrect behavior that throw an exception */
    printf("\nThrowing\n");
    /* ExceptionManager is a Singleton it can't be created more than one time at a time */
    ((ExceptionManager*)new((void*(*)(unsigned long int, va_list*))ExceptionManagerNew, 0))->throw(new((void*(*)(unsigned long int, va_list*))ExampleExceptionNew, 3, "Hello", 0, true));
}

void Catching(Class* pTargetClass, Exception* pException, unsigned long int pArgsCount, va_list* pParams)
{
    unsigned long int* vLong;
    bool* vBoolean;
    printf("\nCatching\n");
    /* use parameters */
    if(pArgsCount > 0)
    {
        vLong = va_arg(*pParams, unsigned long int*);
        if(pArgsCount > 1)
        {
            vBoolean = va_arg(*pParams, bool*);
            printf("\nTransmited parameters :\n\tUnsigned long = %lu,\n\tBoolean = %s.\n", *vLong, (*vBoolean)?"True":"False");
            *vLong = 14;
            *vBoolean = false;
        }
    }

	printf
	(
		"\n%x - %x - %s \n",
		pTargetClass,
		pException,
		pException->Message(pException)->CharPointer
		(
			(String*)pException->Message(pException),
			(char*)0
		)
    );

    /* The only way to reconize a class at execution time */
    if(pException->VirtualTable->IsKindOfTypeID(pException, EXAMPLEEXCEPTION_TYPEID))
    {
        /* Just for use the new implemented method */
        ((ExampleException*)pException)->Example((ExampleException*)pException);
        ((ExampleException*)pException)->Example((ExampleException*)pException);
        ((ExampleException*)pException)->Example((ExampleException*)pException);
        ((ExampleException*)pException)->Example((ExampleException*)pException);
    }
	printf("Catched\n");
}

int main (int argc, char* argv[])
{
    unsigned long int vLong;
    bool vBoolean;
    ExceptionManager* vExceptionManager;
    vBoolean = false;
    vLong = 0x600df00d;
    vExceptionManager = new((void*(*)(unsigned long int, va_list*))ExceptionManagerNew, 0); /* enable Exception Management (try, catch, throw)*/
    if(!vExceptionManager)
    {
        printf("Application not available.");
        return -1;
    }
    vExceptionManager->TryInitialize();
    vExceptionManager->catch(EXCEPTION_TYPEID, (Class*)0, Catching);
    vExceptionManager->try((Class*) 0, Trying, 2, &vLong, &vBoolean);

    printf("\nTransmited parameters :\n\tUnsigned long = %lu,\n\tBoolean = %s.\n", vLong, (vBoolean)?"True":"False");

    delete ((void*)vExceptionManager);
    return 0;
}
